<?php
/**
 * Marco Mounzer
 * m.mounzer@gmail.com
 * @copyright 2013
 */
require_once 'Database.php';

class ObjectForm {

    const TYPE_TEXT = 'text';
    const TYPE_PASSWORD = 'password';
    const TYPE_INPUT = 'input';
    const TYPE_HIDDEN = 'hidden';
    const TYPE_SELECT = 'select';
    const TYPE_CUSTOM = 'custom';
    const TYPE_BOOL = 'bool';

    protected $caption = '';
    protected $formFields = array();
    protected $formFieldsDescriptors = array();

    public function getCaption() {
        return $this->caption;
    }

    private function formFields($prop) {
        return isset($this->formFields[$prop]) ? $this->formFields[$prop] : null;
    }

    private function formFieldsDescriptors($prop) {
        return isset($this->formFieldsDescriptors[$prop]) ? $this->formFieldsDescriptors[$prop] : null;
    }

    /**
     * 
     * @param type $name
     * @param type $data
     * @param type $selected
     * @param type $size
     * @param type $onchange
     * @param type $optgroup
     * @param type $all_field
     * @return string
     */
    public static function DropDownListArray($name, $data, $selected = array(), $size = 1, $onchange = null, $optgroup = false, $all_field = false) {
        $html = "<select name=\"" . strtolower($name) . "\" id=\"" . strtolower($name) . "\" size=\"$size\" onchange=\"$onchange\" style=\"max-width: 200px; min-width: 200px;\">\n";

        if ($all_field) {
            $sel = '';
            if (in_array('-1', $selected))
                $sel = 'selected="selected"';
            $html .= "<option value='-1' $sel>Tutti</option>\n";
        }

        if (!$optgroup) {
            foreach ($data as $v) {
                $sel = '';
                if (in_array($v['id'], $selected))
                    $sel = 'selected="selected"';
                $html .= "<option value=\"" . $v['id'] . "\" $sel>" . $v['descrizione'] . "</option>\n";
            }
        } else {
            foreach ($data as $k => $v) {
                $html .= "<optgroup label=\"" . $k . "\">\n";
                foreach ($v as $v1) {
                    $sel = '';
                    if (in_array($v1['id'], $selected))
                        $sel = 'selected="selected"';
                    $html .= "<option value=\"" . $v1['id'] . "\" $sel>" . $v1['descrizione'] . "</option>\n";
                }
                $html .= "</optgroup>\n";
            }
        }

        $html .= '</select>';
        return $html;
    }

    /**
     * 
     * @param type $name
     * @param type $data
     * @param type $desc_field
     * @param type $selected
     * @param type $size
     * @param type $onchange
     * @param type $optgroup
     * @param type $all_field
     * @return string
     */
    public static function DropDownListObj($name, $data, $desc_field = 'Nome', $selected = array(), $size = 1, $onchange = null, $optgroup = false, $all_field = false) {
        $html = "<select name=\"" . strtolower($name) . "\" id=\"" . strtolower($name) . "\" size=\"$size\" onchange=\"$onchange\" style=\"max-width: 200px; min-width: 200px;\">\n";

        if ($all_field) {
            $sel = '';
            if (in_array('-1', $selected))
                $sel = 'selected="selected"';
            $html .= "<option value='-1' $sel>Tutti</option>\n";
        }

        if (!$optgroup) {
            foreach ($data as $v) {
                $sel = '';
                if (in_array($v->Id, $selected))
                    $sel = 'selected="selected"';

                if (strpos($desc_field, '->') > 0) {
                    $descr_app = explode('->', $desc_field);
                    $descr = $v->{$descr_app[0]};
                    for ($i = 1; $i < count($descr_app); $i++) {
                        $descr = $descr->{$descr_app[$i]};
                    }
                } else {
                    $descr = $v->{$desc_field};
                }

                $html .= "<option value=\"" . $v->Id . "\" $sel>" . $descr . "</option>\n";
            }
        } else {
            foreach ($data as $k => $v) {
                $html .= "<optgroup label=\"" . $k . "\">\n";
                foreach ($v as $v1) {
                    $sel = '';
                    if (in_array($v1->Id, $selected))
                        $sel = 'selected="selected"';
                    $html .= "<option value=\"" . $v1->Id . "\" $sel>" . $v1->{$desc_field} . "</option>\n";
                }
                $html .= "</optgroup>\n";
            }
        }

        $html .= '</select>';
        return $html;
    }

    /**
     *
     * @param string $name
     * @param bool $selected
     * @param int $size
     * @param string $onchange
     * @return string 
     */
    private function DropDownListBool($name, $selected = false, $size = 1, $onchange = null) {
        $html = "<select name=\"" . strtolower($name) . "\" id=\"" . strtolower($name) . "\" size=\"$size\" onchange=\"$onchange\" style=\"max-width: 50px; min-width: 50px;\">\n";

        $selected = ($selected == 'true') || ($selected == 1) || ($selected == true);

        for ($i = 1; $i <= 2; $i++) {
            $sel = '';
            $x = $i % 2 != 0;
            if ($x == $selected)
                $sel = 'selected="selected"';

            $html .= "<option value=\"" . (($i % 2 != 0) ? '1' : '0') . "\" $sel>" . (($i % 2 != 0) ? 'Si' : 'No') . "</option>\n";
        }

        $html .= '</select>';
        return $html;
    }

    /**
     *
     * @return stdClass 
     */
    public function getForm() {
        $reflect = new ReflectionClass($this);
        $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);

        $form = new stdClass();
        $form->name = strtolower(get_class($this));
        $form->caption = $reflect->hasProperty('caption') ? $this->getCaption() : Database::getTableNameFromClassName($this); //get_class($this);
        $form->attributes = array();

        foreach ($props as $prop) {
            $item = new stdClass();
            $item->custom = null;

            $item->values = array();
            if (is_object($this->{$prop->getName()})) {
                $item->name = $prop->getName() . '_id';
                $item->value = $this->{$prop->getName()}->Id;
                if ($this->formFields($prop->getName()) == self::TYPE_SELECT) {

                    if (method_exists($this, 'formFieldsDescriptors') && !is_null($this->formFieldsDescriptors($prop->getName())))
                        $descr_field = $this->formFieldsDescriptors($prop->getName());
                    else
                        throw new Exception('Miss formFieldsDescriptors for: ' . $prop->getName());


                    $item->values = Database::GetIstance()->loadObjects($this->{$prop->getName()}, null, $descr_field);
                }
            } else {
                $item->name = $prop->getName();
                $item->value = $this->{$prop->getName()};
            }

            if (method_exists($this, 'formFields') && !is_null($this->formFields($prop->getName())))
                $item->type = $this->formFields($prop->getName());
            else
                $item->type = self::TYPE_INPUT;

            if (method_exists($this, 'formFieldsDescriptors') && !is_null($this->formFieldsDescriptors($prop->getName())))
                $item->values_descriptor = $this->formFieldsDescriptors($prop->getName());
            else
                $item->values_descriptor = null;

            $form->attributes[strtolower($item->name)] = $item;
        }
        return $form;
    }

    /**
     *
     * @param type $form
     * @param type $readonly
     * @return type 
     */
    public function getFormHtml($form, $readonly = false) {
        $hidden_input = '';
        $onsubmit = '';
        $html = '';
        if (!$readonly)
            $html = '<form action="" method="post" onsubmit="' . $onsubmit . '" name="' . $form->name . '">';

        $html .= '<table><thead><tr><th colspan="2">' . $form->caption . '</th></tr></thead><tbody>';

        foreach ($form->attributes as $item) {
            if ($readonly) {
                $html .= self::getHtmlReadonlyProp($item);
            } else {
                if ($item->type == self::TYPE_HIDDEN)
                    $hidden_input .= self::getHtmlProp($item);
                else
                    $html .= self::getHtmlProp($item);
            }
        }

        $html .= '</tbody><tfoot><tr><td colspan="2">';

        if (!$readonly) {
            $html .= '<input type="submit" name="_save" id="_save" value="Salva" onclick="" style="width: 80px;"/>' . $hidden_input;
            if ($form->attributes['id']->value > 0) {
                $html .= '<input type="submit" name="_delete" onclick="return confirm(\'Sicuro di voler eliminare il dato?\');" id="_delete" value="Cancella" style="width: 80px;"/>';
            }
        }

        $html .= '<button id="close" style="display: none; width: 80px;" onclick="window.close()">Chiudi</button>';

        $html .= '</td></tr></tfoot></table>';
        if (!$readonly)
            $html .= '</form>';

        //$js = '<script type="text/javascript">if(parent.right.document.getElementById(\'' . $form->name . '\')) parent.right.document.getElementById(\'' . $form->name . '\').disabled = false;</script>';

        return $html; // . $js;
    }

    /**
     *
     * @param stdClass $item
     * @return null|string 
     */
    private function getHtmlReadonlyProp($item) {
        if ($item->type == self::TYPE_HIDDEN || $item->type == self::TYPE_CUSTOM)
            return null;

        $html = '<tr><th>' . ucfirst(strpos($item->name, '_id') ? substr($item->name, 0, -3) : $item->name) . '</th><td>';

        if ($item->type == self::TYPE_SELECT) {
            foreach ($item->values as $key => $value) {
                if ($value->Id == $item->value)
                    $html .= $item->values[$key]->{$item->values_descriptor};
            }
        } else
            $html .= $item->value;
        $html .= '</td></tr>';
        return $html;
    }

    /**
     *
     * @param type $item
     * @return string 
     */
    private function getHtmlProp($item) {
        switch ($item->type) {
            case self::TYPE_INPUT:
                $input = '<input size="40" type="text" name="' . strtolower($item->name) . '" id="' . strtolower($item->name) . '" value="' . $item->value . '" />';
                break;

            case self::TYPE_PASSWORD:
                $input = '<input size="40" type="password" name="' . strtolower($item->name) . '" id="' . strtolower($item->name) . '" value="' . $item->value . '" />';
                break;

            case self::TYPE_CUSTOM:
                $input = $item->custom;
                break;

            case self::TYPE_TEXT:
                $input = '<textarea rows="6" cols="32" name="' . strtolower($item->name) . '" id="' . strtolower($item->name) . '">' . $item->value . '</textarea>';
                break;

            case self::TYPE_HIDDEN:
                $input = '<input type="hidden" name="' . strtolower($item->name) . '" id="' . strtolower($item->name) . '" value="' . $item->value . '" />';
                break;

            case self::TYPE_BOOL:
                $input = self::DropDownListBool($item->name, $item->value);
                break;

            case self::TYPE_SELECT:
                $input = self::DropDownListObj($item->name, $item->values, $item->values_descriptor, is_array($item->value) ? $item->value : array($item->value));
                break;

            default:
                $input = "<b>property: '$item->name' undefined type: '$item->type'</b>";
                break;
        }

        if ($item->type == self::TYPE_HIDDEN)
            return $input;

        $html = '<tr><th>' . ucfirst(strpos($item->name, '_id') ? substr($item->name, 0, -3) : $item->name) . '</th><td>';
        $html .= $input;
        $html .= '</td></tr>';

        return $html;
    }

    /**
     *
     * @param array $values
     * @param array $ignore
     * @return type
     * @throws Exception 
     */
    public function setObjectFromFormSubmit($values, $ignore = array()) {
        $reflect = new ReflectionClass($this);
        $props = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);

        foreach ($props as $prop) {
            if (is_object($this->{$prop->getName()})) {
                if (in_array(strtolower($prop->getName()) . '_id', $ignore))
                    continue;

                /*if (isset($values[strtolower($prop->getName()) . '_id']))
                    $this->{$prop->getName()}->Id = $values[strtolower($prop->getName()) . '_id'];
                else
                    throw new Exception('Missing parameter: ' . strtolower($prop->getName()) . '_id');*/


                $obj = Database::GetIstance()->loadObject($this->{$prop->getName()}, $values[strtolower($prop->getName()) . '_id']);
                if ($obj)
                    $this->{$prop->getName()} = $obj;
                else
                    $this->{$prop->getName()} = new $this->{$prop->getName()};
            } else {
                if (in_array(strtolower($prop->getName()), $ignore))
                    continue;

                if (strtolower($prop->getName()) == 'id') {
                    $this->{$prop->getName()} = intval($values[strtolower($prop->getName())]) > 0 ? intval($values[strtolower($prop->getName())]) : 0;
                    continue;
                }

                if (isset($values[strtolower($prop->getName())]))
                    $this->{$prop->getName()} = $values[strtolower($prop->getName())];
                /*else
                    throw new Exception('Missing parameter: ' . strtolower($prop->getName()));*/
            }
        }
        return $this;
    }

    /**
     *
     * @param type $data
     * @param type $descr_field
     * @return type 
     */
    private function orderDataObject($data, $descr_field) {
        $desc = array();
        $ids = array();
        foreach ($data as $key => $row) {

            if (strpos($descr_field, '->') > 0) {
                $descr_app = explode('->', $descr_field);
                $descr = $row->{$descr_app[0]};
                for ($i = 1; $i < count($descr_app); $i++) {
                    $descr = $descr->{$descr_app[$i]};
                }
            } else {
                $descr = $row->{$descr_field};
            }

            $desc[$key] = $descr;
            $ids[$key] = $row->Id;
        }
        array_multisort($desc, SORT_ASC, $ids, SORT_ASC, $data);

        return $data;
    }

    /**
     *
     * @param type $modulo
     * @param type $caption
     * @param type $obj
     * @param type $descr_field
     * @param type $data
     * @param type $optgroup
     * @param type $size
     * @param type $button_new
     * @return string 
     */
    public function ChooserDatabase($modulo, $caption, $descr_field, $data = null, $optgroup = false, $size = 15, $button_new = true) {
        //$name = strtolower(get_class($obj));
        $name = Database::getTableNameFromClassName($this);

        if (is_null($data))
            $data = Database::GetIstance()->loadObjects($this, null, $descr_field);

        $count = count($data);
        if ($optgroup) {
            $count = 0;
            foreach ($data as $v) {
                $count+=count($v);
            }
        }
        $onchange = "this.disabled = true; ChangeCenterPage('$modulo', '$name', this.options[this.selectedIndex].value)";

        $html = '<form action="" method="post" submit="return false;"><table><thead><tr><th>' . ucfirst($caption) . ' [' . $count . ']</td></tr></thead>';

        $html .= '<tbody><tr><td>';
        $html .= ObjectForm::DropDownListObj($name, $data, $descr_field, array(), $size, $onchange, $optgroup);
        $html .= '</td></tr></tbody>';

        $html .= '<tfoot><tr><td>';
        $html .= '<button type="button" onclick="' . $name . '.selectedIndex = -1; ' . $name . '.disabled = true; this.disabled = true; location.reload(true);">Aggiorna</button>';
        if ($button_new) {
            $button_new_obj = $name . ".selectedIndex = -1; ChangeCenterPage('$modulo', '$name', null)";
            $html .= '<button type="button" onclick="' . $button_new_obj . '">Nuovo</button>';
        }
        $html .= '</td></tr></tfoot></table></form>';
        return $html;
    }

}